package cn.iocoder.yudao.module.peizhen.service.buiessorder;

import cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils;
import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;
import cn.iocoder.yudao.module.pay.api.order.PayOrderApi;
import cn.iocoder.yudao.module.pay.api.order.dto.PayOrderCreateReqDTO;
import cn.iocoder.yudao.module.pay.api.order.dto.PayOrderRespDTO;
import cn.iocoder.yudao.module.pay.enums.order.PayOrderStatusEnum;
import cn.iocoder.yudao.module.peizhen.controller.admin.buiessorder.vo.BuiessOrderPageReqVO;
import cn.iocoder.yudao.module.peizhen.controller.admin.buiessorder.vo.BuiessOrderSaveReqVO;
import cn.iocoder.yudao.module.peizhen.dal.dataobject.opencity.ProgramDO;
import cn.iocoder.yudao.module.peizhen.dal.dataobject.staff.StaffDO;
import cn.iocoder.yudao.module.peizhen.dal.mysql.buiessorder.BuiessOrderMapper;
import cn.iocoder.yudao.module.peizhen.dal.mysql.opencity.ProgramMapper;
import cn.iocoder.yudao.module.peizhen.dal.mysql.staff.StaffMapper;
import cn.iocoder.yudao.module.peizhen.enums.BuiessOrderStatusEnum;
import cn.iocoder.yudao.module.peizhen.service.staff.StaffService;
import cn.iocoder.yudao.untils.OrderNumUtil;
import lombok.extern.log4j.Log4j;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;

import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;

import static cn.hutool.core.util.ObjectUtil.notEqual;
import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString;
import static cn.iocoder.yudao.framework.common.util.servlet.ServletUtils.getClientIP;
import cn.iocoder.yudao.module.peizhen.controller.app.buiessorder.vo.*;
import cn.iocoder.yudao.module.peizhen.dal.dataobject.buiessorder.BuiessOrderDO;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;


import java.time.Duration;
import java.time.LocalDateTime;

import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.peizhen.enums.ErrorCodeConstants.*;

/**
 * 订单 Service 实现类
 *
 * @author 芋道源码
 */
@Service
@Validated
@Slf4j
public class BuiessOrderServiceImpl implements BuiessOrderService {

    private static Long PAY_APP_ID=9L;

    @Resource
    private BuiessOrderMapper buiessOrderMapper;


    @Resource
    private PayOrderApi payOrderApi;


    @Resource
    private StaffMapper staffMapper;

    @Resource
    private ProgramMapper programMapper;

    @Override
    @Transactional
    public Long createOrder(AppOrderSaveReqVO createReqVO) {
        //查询是否有未支付的账单
        BuiessOrderDO buiessOrderDO = buiessOrderMapper.selectOne(BuiessOrderDO::getMemberId, createReqVO.getMemberId(), BuiessOrderDO::getStatus, BuiessOrderStatusEnum.PAY.getStatus());
        if (buiessOrderDO!=null){
            throw exception(ORDER_EXIST);
        }
        // 插入
        createReqVO.setNo(OrderNumUtil.generateInvoiceNumber());
        createReqVO.setPayStatus(0);//0等待支付10支付成功
        createReqVO.setStatus(1);//0,填写订单；1在线支付；2服务进行中；3服务完成；4订单取消
        BuiessOrderDO order = BeanUtils.toBean(createReqVO, BuiessOrderDO.class);
        buiessOrderMapper.insert(order);
        //创建支付订单
      Long payorderId= payOrderApi.createOrder(new PayOrderCreateReqDTO().setAppId(PAY_APP_ID).setUserIp(getClientIP()).
                setMerchantOrderId(order.getNo()).setSubject(order.getProgramName()).setBody("").setPrice(order.getPayPrice()).setExpireTime(LocalDateTimeUtils.addTime(Duration.ofMinutes(30L))));
        // 返回
        buiessOrderMapper.updateById(new BuiessOrderDO().setId(order.getId()).setPayOrderId(payorderId));
        return order.getId();
    }

    @Override
    public void updateOrder(AppOrderSaveReqVO updateReqVO) {
        // 校验存在
        validateOrderExists(updateReqVO.getId());
        // 更新
        BuiessOrderDO updateObj = BeanUtils.toBean(updateReqVO, BuiessOrderDO.class);
        buiessOrderMapper.updateById(updateObj);
    }

    @Override
    public void deleteOrder(Long id) {
        // 校验存在
        validateOrderExists(id);
        // 删除
        buiessOrderMapper.deleteById(id);
    }

    private void validateOrderExists(Long id) {
        if (buiessOrderMapper.selectById(id) == null) {
            throw exception(ORDER_NOT_EXISTS);
        }
    }

    @Override
    public BuiessOrderDO getOrder(Long id) {
        return buiessOrderMapper.selectById(id);
    }

    @Override
    public PageResult<BuiessOrderDO> getOrderPage(AppBuiessOrderPageReqVO pageReqVO) {
        return buiessOrderMapper.selectPage(pageReqVO);
    }


    @Override
    public void updateOrderPaid(Long no, Long payOrderId) {
        // 校验并获得支付订单（可支付）
        PayOrderRespDTO payOrder = validateOrderCanPaid(no, payOrderId);
        //0,填写订单；1在线支付；2服务进行中；3服务完成；4订单取消
        BuiessOrderDO buiessOrderDO = new BuiessOrderDO().setStatus(2).setPayStatus(1).setPayTime(LocalDateTime.now())
                .setPayChannelCode(payOrder.getChannelCode());
        // 更新 OrderDO 状态为已支付

        int updateCount = buiessOrderMapper.updateByNo(buiessOrderDO,no);

        if (updateCount == 0) {
            throw exception(ORDER_UPDATE_PAID_STATUS_NOT_UNPAID);
        }
    }


    /**
     * 校验交易订单满足被支付的条件
     *
     * 1. 交易订单未支付
     * 2. 支付单已支付
     *
     * @param id 交易订单编号
     * @param payOrderId 支付订单编号
     * @return 交易订单
     */
    private PayOrderRespDTO validateOrderCanPaid(Long id, Long payOrderId) {
        // 1.1 校验订单是否存在
        BuiessOrderDO buiessOrderDO = buiessOrderMapper.selectOne(BuiessOrderDO::getNo,id);
        if (buiessOrderDO == null) {
            throw exception(ORDER_NOT_EXISTS);
        }
        // 1.2 校验订单未支付
        if (buiessOrderDO.getPayStatus()!=0) {
            log.error("[validateOrderCanPaid][order({}) 不处于待支付状态，请进行处理！order 数据是：{}]",
                    id, toJsonString(buiessOrderDO));
            throw exception(ORDER_UPDATE_PAID_STATUS_NOT_UNPAID);
        }
        // 1.3 校验支付订单匹配
        if (notEqual(buiessOrderDO.getPayOrderId(), payOrderId)) { // 支付单号
            log.error("[validateOrderCanPaid][order({}) 支付单不匹配({})，请进行处理！order 数据是：{}]",
                    id, payOrderId, toJsonString(buiessOrderDO));
            throw exception(ORDER_UPDATE_PAID_FAIL_PAY_ORDER_ID_ERROR);
        }

        // 2.1 校验支付单是否存在
        PayOrderRespDTO payOrder = payOrderApi.getOrder(payOrderId);
        if (payOrder == null) {
            log.error("[validateOrderCanPaid][order({}) payOrder({}) 不存在，请进行处理！]", id, payOrderId);
            throw exception(PAY_ORDER_NOT_FOUND);
        }
        // 2.2 校验支付单已支付
        if (!PayOrderStatusEnum.isSuccess(payOrder.getStatus())) {
            log.error("[validateOrderCanPaid][order({}) payOrder({}) 未支付，请进行处理！payOrder 数据是：{}]",
                    id, payOrderId, toJsonString(payOrder));
            throw exception(ORDER_UPDATE_PAID_FAIL_PAY_ORDER_STATUS_NOT_SUCCESS);
        }
        // 2.3 校验支付金额一致
        if (notEqual(payOrder.getPrice(), buiessOrderDO.getPayPrice())) {
            log.error("[validateDemoOrderCanPaid][order({}) payOrder({}) 支付金额不匹配，请进行处理！order 数据是：{}，payOrder 数据是：{}]",
                    id, payOrderId, toJsonString(buiessOrderDO), toJsonString(payOrder));
            throw exception(ORDER_UPDATE_PAID_FAIL_PAY_PRICE_NOT_MATCH);
        }
        // 2.4 校验支付订单匹配（二次）
        if (notEqual(payOrder.getMerchantOrderId(), id.toString())) {
            log.error("[validateOrderCanPaid][order({}) 支付单不匹配({})，请进行处理！payOrder 数据是：{}]",
                    id, payOrderId, toJsonString(payOrder));
            throw exception(ORDER_UPDATE_PAID_FAIL_PAY_ORDER_ID_ERROR);
        }
        return payOrder;
    }





    @Override
    public Long createBuiessOrder(BuiessOrderSaveReqVO createReqVO) {
        // 插入
        BuiessOrderDO buiessOrder = BeanUtils.toBean(createReqVO, BuiessOrderDO.class);
        buiessOrderMapper.insert(buiessOrder);
        // 返回
        return buiessOrder.getId();
    }

    @Override
    public void updateBuiessOrder(BuiessOrderSaveReqVO updateReqVO) {
        // 校验存在
        validateBuiessOrderExists(updateReqVO.getId());
        // 更新
        BuiessOrderDO updateObj = BeanUtils.toBean(updateReqVO, BuiessOrderDO.class);
        buiessOrderMapper.updateById(updateObj);
    }

    @Override
    public void deleteBuiessOrder(Long id) {
        // 校验存在
        validateBuiessOrderExists(id);
        // 删除
        buiessOrderMapper.deleteById(id);
    }

    private void validateBuiessOrderExists(Long id) {
        if (buiessOrderMapper.selectById(id) == null) {
            throw exception(ORDER_NOT_EXISTS);
        }
    }

    @Override
    public BuiessOrderDO getBuiessOrder(Long id) {
        return buiessOrderMapper.selectById(id);
    }

    @Override
    public PageResult<BuiessOrderDO> getBuiessOrderPage(BuiessOrderPageReqVO pageReqVO) {
        return buiessOrderMapper.selectPage(pageReqVO);
    }

    @Override
    public BuiessOrderDO getBuiessOrderByNo(String no) {
       return buiessOrderMapper.selectOne(BuiessOrderDO::getNo,no);
    }

    @Override
    public void cancelOrderById(Long id) {
        BuiessOrderDO buiessOrder = buiessOrderMapper.selectById(id);
        buiessOrder.setStatus(BuiessOrderStatusEnum.CANCEL.getStatus());
        buiessOrder.setCancelTime(LocalDateTime.now());
        buiessOrderMapper.updateById(buiessOrder);
    }

    @Override
    @Transactional
    public void compleate(Long id) {
        BuiessOrderDO buiessOrder = buiessOrderMapper.selectOne(BuiessOrderDO::getId,id,BuiessOrderDO::getPayStatus,1);
        if (buiessOrder==null){
            throw exception(BUSI_ORDER_NOT_FOUND);
        }
        buiessOrder.setStatus(BuiessOrderStatusEnum.COMPLEATE.getStatus());
        buiessOrder.setFinishTime(LocalDateTime.now());
        buiessOrderMapper.updateById(buiessOrder);

        //对账户进行结算
        StaffDO staff = staffMapper.selectById(buiessOrder.getStaffId());
        ProgramDO programDO = programMapper.selectById(buiessOrder.getProgramId());
        int sum = staff.getBalance()+buiessOrder.getPayPrice()* programDO.getStaffProportion() / 100;
        staff.setBalance(sum);
        staffMapper.updateById(staff);
    }

    @Override
    public void updateBuiessOrderStaff(BuiessOrderSaveReqVO updateReqVO) {
        // 校验存在
        BuiessOrderDO buiessOrderDO = buiessOrderMapper.selectById(updateReqVO.getId());
        // 更新
        buiessOrderDO.setStaffId(updateReqVO.getStaffId());
        buiessOrderDO.setStaffName(updateReqVO.getStaffName());
        buiessOrderMapper.updateById(buiessOrderDO);
    }
}